using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using System.IO;
using DotNetMatrix;
using System.Threading;

namespace Blimpbots.Recognition
{
    public class LiveCamera : ProjectiveCamera, ICamera
    {
        public event EventHandler NewFrame;

        private int _frameNumber = 0;
        public int FrameNumber { get { return _frameNumber; } }

        private EventWaitHandle _newFrameEvent =
            new EventWaitHandle(false, EventResetMode.AutoReset);

        Mutex _mutex = new Mutex();

        private bool _useMJPEG;

        private DateTime _lastFrameTs;
        private DateTime _lastGrabTs;

        private byte[] _lastFrameBytes = null;

        VideoSource.MJPEGStream camStream = new VideoSource.MJPEGStream();

        private string _camera_ip;

        public string Name { 
            get { return _camera_ip; } }

        public string IP
        { set { _camera_ip = value; UpdateMJPEG(); } }

        int width, height;
        public LiveCamera(int width, int height, string camera_ip, CameraProperties properties)
            : base(properties)
        {
            _camera_ip = camera_ip;
            this.width = width;
            this.height = height;

            UpdateMJPEG();
        }

        private void UpdateMJPEG()
        {
            camStream.Login = "root";
            camStream.Password = "z3pp3lin";
            camStream.NewFrame += new VideoSource.CameraEventHandler(camStream_NewFrame);
            //camStream.VideoSource = string.Format("http://{0}/axis-cgi/mjpg/video.cgi?resolution={1}x{2}&compression=30&des_fps=10", _camera_ip, width, height);
            camStream.VideoSource = string.Format("http://{0}/axis-cgi/mjpg/video.cgi?resolution={1}x{2}&des_fps=8", _camera_ip, width, height);

            // Powers ACE Hardware Cam
            //camStream.VideoSource = "http://www.powershardware.com/axis/cam_mjpeg.php";

        }

        public void Start() { camStream.Start(); _useMJPEG = true; }
        public void Stop() { _useMJPEG = false; camStream.Stop(); _newFrameEvent.Set(); }

        void camStream_NewFrame(object sender, VideoSource.CameraEventArgs e)
        {
            _mutex.WaitOne();
            // Remember the latest frame
            _lastFrameTs = DateTime.Now;
            _lastFrameBytes = e.FrameBytes;
            _mutex.ReleaseMutex();
            _newFrameEvent.Set();

            // Notify external callers
            if (NewFrame != null)
                NewFrame(this, null);
        }

        /// <summary>
        /// The timestamp of the frame most recently accessed
        /// </summary>
        public DateTime LastFrameTimestamp
        {
            get { return _lastGrabTs; }
        }

        public Bitmap LastFrame
        {
            get
            {
                if (!_useMJPEG)
                    return CaptureFrame();

                _newFrameEvent.WaitOne();
                _mutex.WaitOne();


                // If the mode switched in between...
                if (!_useMJPEG)
                {
                    _mutex.ReleaseMutex();
                    return CaptureFrame();
                }
                else
                {
                    // Render the latest frame
                    Bitmap bmp = (Bitmap)Bitmap.FromStream(
                        new MemoryStream(_lastFrameBytes, 0, _lastFrameBytes.Length));

                    // Store when it was captured
                    _lastGrabTs = _lastFrameTs;

                    _mutex.ReleaseMutex();

                    return bmp;
                }
            }
        }

        
        byte[] rawFrame;

        public byte[] RawFrame { get { return rawFrame; } }



        /// <summary>
        /// Downloads a frame from the Axis camera.
        /// </summary>
        /// <param name="width">Desired width</param>
        /// <param name="height">Desired height</param>
        /// <returns>Bitmap of the scene</returns>
        public Bitmap CaptureFrame()
        {
            string url = string.Format("http://{0}/axis-cgi/jpg/image.cgi?resolution={1}x{2}", _camera_ip, width, height);
            _lastGrabTs = DateTime.Now;

            try
            {
                using (System.Net.WebClient c = new System.Net.WebClient())
                {
                    Bitmap b = null;
                    c.Credentials = new System.Net.NetworkCredential("root", "z3pp3lin");
                    rawFrame = c.DownloadData(url);

                    using (MemoryStream ms = new MemoryStream(rawFrame))
                    {
                        b = (Bitmap)Bitmap.FromStream(ms);
                    }

                    return b;

                    //// Copy the image to get it into an acceptable pixel format
                    //frame = new Bitmap(b.Width, b.Height);

                    //Graphics g = Graphics.FromImage(frame);
                    //g.DrawImage(b, 0, 0, b.Width, b.Height);
                    //g.Dispose();
                }
            }
            catch
            {
                return null;
            }

        }

    }
}
